#pragma once

namespace cpfs {

typedef int64_t Blkno;
#define PRIdBLKNO PRId64

typedef uint32_t Blksize;

typedef Blkno Ino;
#define PRIdINO PRIdBLKNO

typedef int64_t Offset;
#define PRIdOFFSET PRId64

size_t const fsidentSize = 32;
struct TYPEATTR_PACKED Bootrec {
    char fsident[fsidentSize]; // 0
    Blkno blkcount; // 32
    Blksize blksize; // 40
    uint32_t serial; // 44
};
CHECK_TYPE_SIZE(Bootrec, 48);

typedef int8_t Depth;
struct TYPEATTR_PACKED Data {
    Offset size; // 8
    Blkno root; // 16
    Depth depth; // 17
    char UNUSED_MEMBER[3]; // 20
};
CHECK_TYPE_SIZE(Data, 20);
static struct Data const DATA_INIT = {0, -1, 0};

struct TYPEATTR_PACKED Inode {
    Ino ino; // 8
	uint8_t type; // 9
    char UNUSED_MEMBER[1]; // 10
	CpfsPerms perms; // 12
    int32_t nlink; // 16
    uint32_t uid; // 20
    uint32_t gid; // 24
    uint64_t rdev; // 32
    CpfsTime atime; // 40
    CpfsTime mtime; // 48
    CpfsTime ctime; // 56
    struct Data data; // 76
    Blkno inline_data[0]; // 76
};
CHECK_TYPE_SIZE(Inode, 76);
static_assert(
    sizeof(struct Inode) <= 512,
    "Inode size must not exceed smallest allowable block size.");

static size_t const CPFS_NAME_MAX = 255;
typedef uint8_t DeType;
struct Dirent {
    Ino ino;
    char name[CPFS_NAME_MAX];
    DeType type;
    Dirent() : ino(-1), type(0) { name[0] = '\0'; }
};
CHECK_TYPE_SIZE(Dirent, 264);

} // namespace cpfs {
